package com.wudl.core

import org.apache.spark.util.AccumulatorV2
import org.apache.spark.{SparkConf, SparkContext}

import scala.collection.mutable

/**
 *
 * @author wudl
 * @create 2021/6/17 17:08
 * @description  自定义累加器然 统计单词出现的次数
 */
object AccumulatorWordCount {
  def main(args: Array[String]): Unit = {

    val sparkConf = new SparkConf().setMaster("local[1]").setAppName("AccunlatorCount")
    val sc = new SparkContext(sparkConf)
    val dataRdd = sc.makeRDD(List("java", "spark", "flink", "hbase", "spark"))


    val mywcc = new myAccumulator()
    // 向spark进行注册
    sc.register(mywcc, "workCountWcc")
    dataRdd.foreach(
      word => {
        mywcc.add(word)
      }
    )

    println(mywcc.value)
    sc.stop()


  }

  /**
   * 自定义累加器
   */

  class myAccumulator extends AccumulatorV2[String, mutable.Map[String, Long]] {

    private var wcMap = mutable.Map[String, Long]()


    /** 设置初始化状态 */
    override def isZero: Boolean = {
      wcMap.isEmpty
    }

    override def copy(): AccumulatorV2[String, mutable.Map[String, Long]] = {
      new myAccumulator
    }

    // 清空上一次的内容
    override def reset(): Unit = {
      wcMap.clear()
    }
    // 添加新元素并且更新
    override def add(v: String): Unit = {
      val newCnt = wcMap.getOrElse(v, 0L) + 1
      wcMap.update(v, newCnt)
    }

    /**
     * Driver 合并多个累加器
     *
     * @param other
     */
    override def merge(other: AccumulatorV2[String, mutable.Map[String, Long]]): Unit = {
      val map1 = this.wcMap
      val map2 = other.value
      map2.foreach {
        case (word, count) => {
          val newCount = map1.getOrElse(word, 0L) + count
          map1.update(word, newCount)
        }
      }
    }

    /**
     * 累加的结果
     *
     * @return
     */
    override def value: mutable.Map[String, Long] = {
      wcMap
    }
  }
}
